package com.squirrel.auxiliary;

import com.squirrel.DataBeanConfig;
import com.squirrel.constant.DataDriver;
import com.squirrel.pojo.ColumnType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedCaseInsensitiveMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wangyan
 */
@Scope
@Repository
public class TableFieldsType {
    private static final Logger log = LoggerFactory.getLogger(TableFieldsType.class);

    private JdbcTemplate jdbcTemplate;
    @Autowired(required = false)
    private DataBeanConfig dataBeanConfig;

    private static String driverClassName;

    //默认缓存表的数量
    @Value("${spring.datasource.cacheTableNum}")
    private static int cacheTableNum = 1024;
    private static Map<String, Map<String, String>> columnTypeCache = new ConcurrentHashMap();
    //命中次数，超过缓存容量的时候，将命中次数较小的去掉
    private static Map<String, Integer> hitTableNum = new ConcurrentHashMap();

    /**
     * oracle数据库
     */
    private final static String ORACLE_SELECT_COLUMN_SQL = "SELECT COLUMN_NAME,DATA_TYPE||DATA_PRECISION AS DATA_TYPE FROM USER_TAB_COLUMNS WHERE TABLE_NAME=?";
    /**
     * postgres数据库
     */
    private final static String PG_SELECT_COLUMN_SQL = "SELECT column_name as COLUMN_NAME,udt_name as DATA_TYPE FROM information_schema.COLUMNS WHERE TABLE_NAME = ?";

    /**
     * sqlServer数据库
     */
    private final static String SQLSERVER_SELECT_COLUMN_SQL = "select COLUMN_NAME,DATA_TYPE from INFORMATION_SCHEMA.COLUMNS where table_name = ?";

    /**
     * mysql数据库
     */
    private final static String MYSQL_SELECT_COLUMN_SQL = "select COLUMN_NAME,DATA_TYPE from information_schema.columns where table_name = ?";


    public void setJdbcTemple(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public Map<String, String> getColumnType(String tableName) {
        if (columnTypeCache.size() == cacheTableNum) {
            //对hitTableNum排序，删除最小命中次数缓存
            List<Map.Entry<String, Integer>> mapList = new ArrayList<>(hitTableNum.entrySet());
            mapList.sort((o2, o1) -> o2.getValue() - o1.getValue());
            for (int i = 0; i < mapList.size(); i++) {
                if (i < cacheTableNum / 4) {
                    Map.Entry<String, Integer> entry = mapList.get(i);
                    //删除四分之一缓存
                    hitTableNum.remove(entry.getKey());
                    columnTypeCache.remove(entry.getKey());
                }
                break;
            }
        }
        if (hitTableNum.get(tableName) == null) {
            hitTableNum.put(tableName, 1);
        } else {
            hitTableNum.put(tableName, hitTableNum.get(tableName) + 1);
        }
        if (!CollectionUtils.isEmpty(columnTypeCache.get(tableName))) {
            return columnTypeCache.get(tableName);
        }
        RowMapper<ColumnType> rowMapper = new BeanPropertyRowMapper<>(ColumnType.class);
        Map<String, String> linkedCaseMap = new LinkedCaseInsensitiveMap<>();
        List<ColumnType> columnTypes = null;
        driverClassName = dataBeanConfig.getDriverClassName();
        log.debug("加载数据库驱动:{}", driverClassName);
        if (DataDriver.ORACLE_DRIVER.equals(driverClassName)) {
            columnTypes = jdbcTemplate.query(ORACLE_SELECT_COLUMN_SQL, rowMapper, tableName.toUpperCase());
        } else if (DataDriver.PG_DRIVER.equals(driverClassName)) {
            columnTypes = jdbcTemplate.query(PG_SELECT_COLUMN_SQL, rowMapper, tableName.toLowerCase());
        } else if (DataDriver.SQLSERVER_DRIVER.equals(driverClassName)) {
            columnTypes = jdbcTemplate.query(SQLSERVER_SELECT_COLUMN_SQL, rowMapper, tableName.toLowerCase());
        } else if (DataDriver.MYSQL_DRIVER.equals(driverClassName)) {
            columnTypes = jdbcTemplate.query(MYSQL_SELECT_COLUMN_SQL, rowMapper, tableName.toLowerCase());
        }
        if (columnTypes != null && !columnTypes.isEmpty()) {
            columnTypes.forEach(columnType -> {
                linkedCaseMap.put(columnType.getColumnName(), columnType.getDataType());
            });
        }
        //添加缓存
        columnTypeCache.put(tableName, linkedCaseMap);
        return linkedCaseMap;
    }
}
